package com.example.bankmanage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.bankmanage.Common.UserContext;
import com.example.bankmanage.Common.UserInfoDTO;
import com.example.bankmanage.convention.exception.ClientException;
import com.example.bankmanage.dto.rep.UpdateEmpInfoServiceReqDTO;
import com.example.bankmanage.dto.rep.UserLoginReqDTO;
import com.example.bankmanage.dto.rep.UserRegisterReqDTO;
import com.example.bankmanage.dto.resq.UserLoginRespDTO;
import com.example.bankmanage.entity.users;
import com.example.bankmanage.mapper.UserMapper;
import com.example.bankmanage.result.Result;
import com.example.bankmanage.service.UserService;
import com.example.bankmanage.util.JwtUtil;
//import com.example.bankmanage.util.ThreadLocalUtil;
import com.example.bankmanage.util.ThreadLocalUtil;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.example.bankmanage.constant.RedisCacheConstant.USER_LOGIN_KEY;
import static com.example.bankmanage.constant.RedisCacheConstant.USER_REGISTER_KEY;
import static com.example.bankmanage.convention.errorcode.BaseErrorCode.USER_NAME_EXIST_ERROR;
import static com.example.bankmanage.convention.errorcode.UserErrorCodeEnum.*;

@Service
@SuppressWarnings("all")
public class UserServiceimpl extends ServiceImpl<UserMapper, users> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired(required = false)
    private RBloomFilter<String> userRegisterCachePenetrationBloomFilter;
//    @Override
//    public UserLoginRespDTO login(UserLoginReqDTO userLoginReqDTO) {
//        LambdaQueryWrapper<users> queryWrapper = Wrappers.lambdaQuery(users.class)
//                .eq(users::getUsername, userLoginReqDTO.getUsername())
//                .eq(users::getPassword, userLoginReqDTO.getPassword());
//        users user = baseMapper.selectOne(queryWrapper);
//        if (user == null) {
//            throw new ClientException("用户不存在");
//        }
//
//    }

    @Override
    public UserLoginRespDTO login(UserLoginReqDTO userLoginReqDTO) {

        LambdaQueryWrapper<users> QueryWrapper = Wrappers.lambdaQuery(users.class)
                .eq(users::getUsername, userLoginReqDTO.getUsername())
                .eq(users::getPassword, userLoginReqDTO.getPassword());
        users users1 = baseMapper.selectOne(QueryWrapper);
        if (users1 == null) {
            throw new ClientException("用户不存在");
        }
        Map<String,Object> map = new HashMap<>();
        map.put("userId",users1.getUserId());
        map.put("username",users1.getUsername());
        ThreadLocalUtil.set(map);
        System.out.println(map);
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setUserId(users1.getUserId());
        userInfoDTO.setUsername(users1.getUsername());
        UserContext.setUser(userInfoDTO);
        UserContext.getUserCopy();
//        Map<String,Object> map = new HashMap<>();
//        map.put("userId",users1.getUserId());
//        map.put("username",users1.getUsername());
//        ThreadLocalUtil.set(map);
//        String token = JwtUtil.genToken(map);
        System.out.println("------"+UserContext.getUserId());
        System.out.println(UserContext.getUsername());
        Map<Object, Object> hasLoginMap = stringRedisTemplate.opsForHash().entries(USER_LOGIN_KEY + userLoginReqDTO.getUsername());
//        ThreadLocalUtil.set(hasLoginMap);
        if (CollUtil.isNotEmpty(hasLoginMap)) {
            stringRedisTemplate.expire(USER_LOGIN_KEY + userLoginReqDTO.getUsername(), 30L, TimeUnit.MINUTES);
            String token = hasLoginMap.keySet().stream()
                    .findFirst()
                    .map(Object::toString)
                    .orElseThrow(() -> new ClientException("用户登录错误"));
            return new UserLoginRespDTO(token);
        }
        /**
         * Hash
         * Key：login_用户名
         * Value：
         *  Key：token标识
         *  Val：JSON 字符串（用户信息）
         */
        String uuid = UUID.randomUUID().toString();
//        stringRedisTemplate.opsForHash().put(USER_LOGIN_KEY + userLoginReqDTO.getUsername(), uuid, JSON.toJSONString(users));
        stringRedisTemplate.expire(USER_LOGIN_KEY + userLoginReqDTO.getUsername(), 30L, TimeUnit.MINUTES);
        return new UserLoginRespDTO(uuid);
    }

    @Transactional
    @Override
    public void register(UserRegisterReqDTO userRegisterReqDTO) {
        System.out.println(userRegisterReqDTO.toString());
        if (!hasUsername(userRegisterReqDTO.getUsername())) {
            throw new ClientException(USER_NAME_EXIST_ERROR);
        }
        RLock lock = redissonClient.getLock(USER_REGISTER_KEY + userRegisterReqDTO.getUsername());
        if (!lock.tryLock()) {
            throw new ClientException(USER_NAME_EXIST_ERROR);
        }
        try {
//            System.out.println("执行力插入");
            int insert = baseMapper.insert(BeanUtil.toBean(userRegisterReqDTO, users.class));
            if (insert < 1) {
                throw new ClientException(USER_SAVE_ERROR);
            }
            userRegisterCachePenetrationBloomFilter.add(userRegisterReqDTO.getUsername());
        } catch (DuplicateKeyException ex) {
            throw new ClientException(USER_EXIST);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Boolean hasUsername(String username) {
        return !userRegisterCachePenetrationBloomFilter.contains(username);
    }

    @Override
    public users getEmpInfoService() {
//        Map<String,Object> map = ThreadLocalUtil.get();
//        System.out.println(map);
        LambdaQueryWrapper<users> QueryWrapper= Wrappers.lambdaQuery(users.class)
                .eq(users::getUserId,UserContext.getUserId());
        users users1 = baseMapper.selectOne(QueryWrapper);
        return users1;
    }

    @Override
    public void updateEmpInfoService(UpdateEmpInfoServiceReqDTO requestParam) {
//        Map<String,Object> map = ThreadLocalUtil.get();
        LambdaUpdateWrapper<users> UpdateWrapper = Wrappers.lambdaUpdate(users.class)
                .eq(users::getUserId, UserContext.getUserId());
        int update = baseMapper.update(UpdateWrapper);
        if (update < 1) {
            throw new ClientException(USER_UPDATE_ERROR);
        }
    }
}
